﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace SimpleRedisClinet
{
    /// <summary>
    /// simple redis client class
    /// yangmeng(hvbird@gmail.com)
    /// 2011-01-21
    /// </summary>
    public class RedisList : RedisBase
    {
        public RedisList(string hostip, int port)
            : base(hostip,port)
        {
            
        }

        public bool AppendToTail<T>(string key, T obj)
        {
            check_key(key);

            System.Text.StringBuilder sb = new StringBuilder();
            sb.Append("RPUSH ");

            sb.Append(key);
            sb.Append(" ");
            string strvalue = get_serializer_str<T>(obj);
            sb.Append(System.Text.Encoding.UTF8.GetByteCount(strvalue));
            sb.Append("\r\n");
            sb.Append(strvalue);
            sb.Append("\r\n");


            ResponseClass ret = send_and_receive(sb.ToString());

            if (ret.Number > 0)
                return true;

            return false;
        }

        public bool AppendToHead<T>(string key, T obj)
        {
            check_key(key);

            System.Text.StringBuilder sb = new StringBuilder();
            sb.Append("LPUSH ");

            sb.Append(key);
            sb.Append(" ");
            string strvalue = get_serializer_str<T>(obj);
            sb.Append(System.Text.Encoding.UTF8.GetByteCount(strvalue));
            sb.Append("\r\n");
            sb.Append(strvalue);
            sb.Append("\r\n");


            ResponseClass ret = send_and_receive(sb.ToString());

            if (ret.Number > 0)
                return true;

            return false;
        }

        public T PopHead<T>(string key)
        {
            check_key(key);

            // not exists or data type error
            if (GetDataType(key) != RedisDataType.List)
                return default(T);

            string cmdstr = "LPOP " + key + "\r\n";

            ResponseClass ret = send_and_receive(cmdstr);

            if (ret.Strings.Count > 0)
            {
                T retobj = get_deserialized_obj<T>(ret.Strings[0]);
                return retobj;
            }

            return default(T);
        }

        public T PopTail<T>(string key)
        {
            check_key(key);

            // not exists or data type error
            if (GetDataType(key) != RedisDataType.List)
                return default(T);

            string cmdstr = "RPOP " + key + "\r\n";

            ResponseClass ret = send_and_receive(cmdstr);

            if (ret.Strings.Count > 0)
            {
                T retobj = get_deserialized_obj<T>(ret.Strings[0]);
                return retobj;
            }

            return default(T);
        }

        public int GetItemCount(string key)
        {
            check_key(key);

            string cmdstr = "LLEN " + key + "\r\n";

            ResponseClass ret = send_and_receive(cmdstr);

            return ret.Number;
        }

        public T GetItemIndex<T>(string key,int index)
        {
            check_key(key);

            // not exists or data type error
            if (GetDataType(key) != RedisDataType.List)
                return default(T);

            string cmdstr = "LINDEX " + key + " " +index+ "\r\n";

            ResponseClass ret = send_and_receive(cmdstr);

            if (ret.Strings.Count > 0)
            {
                T retobj = get_deserialized_obj<T>(ret.Strings[0]);
                return retobj;
            }

            return default(T);
        }

        public List<T> GetRangeItems<T>(string key, int start, int end)
        {
            check_key(key);

            List<T> retlist = new List<T>();

            // not exists or data type error
            if (GetDataType(key) != RedisDataType.List)
                return retlist;

            string cmdstr = "LRANGE " + key + " " + start + " " + end + "\r\n";

            ResponseClass ret = send_and_receive(cmdstr);

            for (int i = 0; i < ret.Strings.Count; i ++)
            {
                T retobj = get_deserialized_obj<T>(ret.Strings[i]);

                retlist.Add(retobj);
            }

            return retlist;
        }

        /// <summary>
        /// remove items from list
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="count">removed max number, 0:delete all  matched 1:remove first matched -1:remove last matched</param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int RemoveItems<T>(string key, int count, T obj)
        {
            check_key(key);

            System.Text.StringBuilder sb = new StringBuilder();
            sb.Append("LREM ");

            sb.Append(key);
            sb.Append(" ");
            sb.Append(count + " ");
            string strvalue = get_serializer_str<T>(obj);
            sb.Append(System.Text.Encoding.UTF8.GetByteCount(strvalue));
            sb.Append("\r\n");
            sb.Append(strvalue);
            sb.Append("\r\n");


            ResponseClass ret = send_and_receive(sb.ToString());

            return ret.Number;
        }
    }
}
